{$MODE objfpc}
unit PythonTupleObject;

// Another generally useful object type is a tuple of object pointers.
// For Python, this is an immutable type.  C code can change the tuple items
// (but not their number), and even use tuples are general-purpose arrays of
// object references, but in general only brand new tuples should be mutated,
// not ones that might already have been exposed to Python code.

// *** WARNING *** PyTuple_SetItem does not increment the new item's reference
// count, but does decrement the reference count of the item it replaces,
// if not nil.  It does *decrement* the reference count if it is *not*
// inserted in the tuple.  Similarly, PyTuple_GetItem does not increment the
// returned item's reference count.

interface
  uses Python, PythonTypes;

  type
    PyTupleObject = record
  	  //PyObject_VAR_HEAD
  		ob_refcnt: 	Py_ssize_t;
  		ob_type: 	  PyTypeObjectPtr;
      ob_size:    Py_ssize_t;
      
      ob_item:    ^PyObjectPtr; //Map array as pointer...

      // ob_item contains space for 'ob_size' elements.
      // Items must normally not be NULL, except during construction when
      // the tuple is not yet visible outside the function that builds it.
    end;
    PyTupleObjectPtr = ^PyTupleObject;

  var
    PyTuple_Type: PyTypeObject; cvar; external;


  function PyTuple_New(size: Py_ssize_t): PyObjectPtr; cdecl; external;
  function PyTuple_Size(obj: PyObjectPtr): Py_ssize_t; cdecl; external;
  function PyTuple_GetItem(obj: PyObjectPtr; idx: Py_ssize_t): PyObjectPtr; cdecl; external;
  function PyTuple_SetItem(obj: PyObjectPtr; idx: Py_ssize_t; value: PyObjectPtr): Integer; cdecl; external;
  
  function PyTuple_GetSlice(obj: PyObjectPtr; start, endSlice: Py_ssize_t): PyObjectPtr; cdecl; external;
  function _PyTuple_Resize(obj: PyObjectPtrPtr; newSize: Py_ssize_t): Integer; cdecl; external;
  //function PyTuple_Pack(Py_ssize_t, ...);

  function PyTuple_Check(op: PyObjectPtr): Boolean;
  function PyTuple_CheckExact(op: Pointer): Boolean;

  // Macro, trading safety for speed
  //function PyTuple_GET_ITEM(op: PyTupleObjectPtr; i: Integer): PyObjectPtr;
  //function PyTuple_GET_SIZE(op: PyTupleObjectPtr): Py_ssize_t;

  // Macro, *only* to be used to fill in brand new tuples
  //procedure PyTuple_SET_ITEM(op: PyTupleObjectPtr; i: Integer; v: PyObjectPtr);


  function PyTuple_Pack(contents: Array of PyObjectPtr): PyObjectPtr;
implementation
  uses PythonObject;
  
  function PyTuple_Check(op: PyObjectPtr): Boolean;
  begin
    result := PyObject_TypeCheck(op, @PyTuple_Type);
  end;

  function PyTuple_CheckExact(op: Pointer): Boolean;
  begin
    result := (PyObjectPtr(op)^.ob_type = @PyTuple_Type);
  end;
  
 { function PyTuple_GET_ITEM(op: PyTupleObjectPtr; i: Integer): PyObjectPtr;
  begin
    result := (op^.ob_item + i)^;
  end;
  
  function PyTuple_GET_SIZE(op: PyTupleObjectPtr): Py_ssize_t;
  begin
    result := op^.ob_size;
  end;
  
  procedure PyTuple_SET_ITEM(op: PyTupleObjectPtr; i: Integer; v: PyObjectPtr);
  begin
     (op^.ob_item + i)^ := v;
  end;}
  
  function PyTuple_Pack(contents: Array of PyObjectPtr): PyObjectPtr;
  var
    i: Py_ssize_t;
    op: PyTupleObjectPtr;
  begin
    result := PyTuple_New(Length(contents));
    op := PyTupleObjectPtr(result);
    for i := 0 to Length(contents) do
    begin
      (op^.ob_item + i)^ := contents[i];
      Py_IncRef(contents[i]);
    end;
  end;
end.